﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace IPL
{
    public class Lexer
    {
        #region Properties
        private string _sourceString;
        private IList<Token> _sourceTokenList { get; set; }
        private Hashtable _constants { get; set; }
        private string[] _sourceLineArray;
        private int _currentTokenListIndex;
        #endregion

        #region Constructors
        public Lexer(string source)
        {
            _sourceString = source;
            _constants = new Hashtable();
            source = Regex.Replace(source, @"[+=,;:*<>(){}[\]]", " $& ");
            source = Regex.Replace(source, "[ \t]{2,}", " ");
            _sourceTokenList = new List<Token>();
            _currentTokenListIndex = 0;
            int currentLineIndex = 0;
            string[] split = { "\r\n" };
            _sourceLineArray = source.Split(split, StringSplitOptions.None);
            foreach (string sourceLine in _sourceLineArray)
            {
                currentLineIndex++;
                if (sourceLine.StartsWith("--") || sourceLine.Trim().Equals("")) continue;
                string[] sla = sourceLine.Trim().Split(' ');
                foreach (string lexem in sla)
                {
                    if (lexem.Equals("--")) break;
                    _sourceTokenList.Add(Token.New(lexem, currentLineIndex));
                }
            }
            _sourceTokenList.Add(new EndToken("EOF", currentLineIndex, TokenType.End));
        }
        #endregion

        #region Private Methods
        private Token _getToken(int index)
        {
            if (index >= _sourceTokenList.Count || index < 0) index = _sourceTokenList.Count - 1;
            if (index < 0) index = 0;
            Token result = _sourceTokenList[index];

            if (_constants.ContainsKey(result.Value))
            {
                var temp = (Token)_constants[result.Value];
                temp.Lexem = result.Lexem;
                temp.LineNum = result.LineNum;
                result = temp;
            }

            return result;
        }
        #endregion

        #region Public Methods
        public void AddConstant(string key, Token value)
        {
            _constants[key] = value;
        }

        public Token Current()
        {
            return _getToken(_currentTokenListIndex);
        }

        public Token Next()
        {
            return LookAhead(1);
        }

        public void Accept()
        {
            if (!End()) _currentTokenListIndex++;
        }

        public Token LookAhead(int ahead)
        {
            return _getToken(_currentTokenListIndex + ahead);
        }

        public Token LookBehind(int behind)
        {
            return _getToken(_currentTokenListIndex - behind);
        }

        public bool End()
        {
            if (Current() is EndToken) return true;
            else return false;
            //if (_sourceTokenList.Count() > _currentTokenListIndex) return false;
            //else return true;
        }
        #endregion
    }
}
